AWS CodeDeploy を使って Rails アプリケーションをデプロイしてみた
Rails アプリケーションをデプロイしてみよう
昨日の re:Invent で発表された AWS CodeDeploy (以下 CodeDeploy) を使って GitHub リポジトリで管理している Rails アプリケーションを EC2 インスタンスにデプロイしてみました。いままでは Capistrano を利用してデプロイを行うのが主流でしたが、果たして CodeDeploy はこれに変わるサービスなのか!?と思いながら試してみることにしました。
なお、サンプルサイトのデプロイ手順は以下で紹介していますので、こちらもあわせてご覧ください!
EC2 インスタンスの環境構築
今回の要件を達成するために、EC2 インスタンスには以下の環境構築が必要です。この手順については今回は割愛させていただきます。ちなみに私は Chef を利用して行いました。
- Ruby (rbenv または rvm を推奨)
- Nginx (Rails アプリの動作確認用)
- AWS CodeDeploy Agent
特に AWS CodeDeploy Agent が真新しいですが、これは CodeDeploy の対象となるインスタンスには必須になります。インストール実行ファイルを S3 からダウンロードする操作が発生するため s3:Get と s3:List の実行が許可されている IAM Role を指定して起動している必要があります。
AWS CodeDeploy Agent のインストールコマンドは以下の通りです(us-east-1 の場合)。
$ sudo yum update $ sudo yum install aws-cli $ cd /home/ec2-user $ aws s3 cp s3://aws-codedeploy-us-east-1/latest/install . --region us-east-1 $ chmod +x ./install $ sudo ./install auto
AppSpec ファイルの追加
ソースコードでは、CodeDeploy がデプロイ設定を読み込むための appspec.yml ファイルを作成しておく必要があります。YAML で書きます。また BeforeInstall や AfterInstall といった設定を追加すると、デプロイのライフサイクルをフックして処理を追加することができます。処理自体はシェルスクリプトファイルで作ります。
version: 0.0 os: linux files: - source: / destination: /var/www/sample-app permissions: - object: /var/www/ pattern: "**" mode: 775 hooks: ApplicationStop: - location: scripts/stop_server.sh timeout: 300 runas: root BeforeInstall: - location: scripts/clean.sh timeout: 300 runas: root AfterInstall: - location: scripts/bundle_install.sh timeout: 300 runas: root ApplicationStart: - location: scripts/start_server.sh timeout: 300 runas: root
今回は、デプロイ済みのソースのクリーン、Bundler を使った Gem ファイルのインストール、Unicorn サーバーを起動するコマンドを追加します。
#!/bin/bash su -l deploy -c 'kill -KILL -s QUIT `cat /var/www/sample-app/tmp/pids/unicorn.pid`'
#!/bin/bash sudo rm -rf /var/www/sample-app
#!/bin/bash su -l deploy -c 'cd /var/www/sample-app && bundle install --path vendor/bundle'
#!/bin/bash su -l deploy -c 'cd /var/www/sample-app && bundle exec unicorn -D -E production -c config/unicorn.rb'
2014/11/18 一部修正しました。
Application の作成
事前準備が済んだところで、CodeDeploy の Application を作成しましょう。まずはこちらにアクセスし「Get Started Now」をクリックします。
今回は「Custom Deployment」を選択します。
新規アプリーケーションの設定を行っていきます。Application Name は「sample-app」、Deployment Group Nameは「sample-app-deplpoyment-group」にしました。
Add Amazon EC2 Instances
デプロイ対象の EC2 インスタンスを指定します。今回は既存の EC2 インスタンスを指定していますが、Auto Scaling Group を指定することもできます。
Deployment Configuration
どのようにデプロイを実行するか、またデプロイの成功/失敗をどのように扱うかという設定項目です。
デフォルトで用意されている設定は次の通りです。なお、自分で作成することもできます。
CodeDeployDefault.AllAtOnce | 一度にすべてのインスタンスにデプロイする。最低1つのインスタンスにデプロイが成功した場合、全体のデプロイが成功したものとする。すべてのインスタンスへのデプロイが失敗した場合、全体のデプロイが失敗したものとする。 |
---|---|
CodeDeployDefault.OneAtTime | インスタンス1つずつにデプロイする。全てのインスタンスにデプロイが成功した場合、全体のデプロイが成功したものとする。デプロイが失敗した時点で失敗と扱われるが、既にデプロイが成功したインスタンスはそのまま。 |
CodeDeployDefault.HalfAtTime | 一度に総インスタンス数の半分までデプロイする。総インスタンス数の半分までデプロイが成功した場合、全体のデプロイが成功したものとする。全体のデプロイが失敗した場合でも、既にデプロイが成功したインスタンスはそのまま。 |
CodeDeployDefault.HalfAtTime はちょっと特殊ですね。ちなみにデプロイ対象が複数のインスタンスのときだけ効果があるようなので、デプロイ対象が1つのインスタンスだけの場合、どれを選んでも同じです。デフォルトは CodeDeployDefault.OneAtTime が設定されています。
Service Role
CodeDeploy が EC2 インスタンスにアクセスするときに使用するロールの設定項目です。
サンプルのロールと同様のロールを作成して使うだけで良いと思います。
{ "Statement": [ { "Action": [ "ec2:Describe*" ], "Effect": "Allow", "Resource": [ "*" ] }, { "Action": [ "autoscaling:CompleteLifecycleAction", "autoscaling:DeleteLifecycleHook", "autoscaling:DescribeLifecycleHooks", "autoscaling:DescribeAutoScalingGroups", "autoscaling:PutLifecycleHook", "autoscaling:RecordLifecycleActionHeartbeat" ], "Effect": "Allow", "Resource": [ "*" ] } ] }
Trusted Entities は次のような感じです。
{ "Version": "2008-10-17", "Statement": [ { "Sid": "1", "Effect": "Allow", "Principal": { "Service": [ "codedeploy.us-west-2.amazonaws.com", "codedeploy.us-east-1.amazonaws.com" ] }, "Action": "sts:AssumeRole" } ] }
デプロイを実行する
さて、いよいよデプロイです!「Deploy New Revision」をクリックします。
今回は GitHub リポジトリで管理しているアプリケーションをデプロイしたいので、Revision Type は「My application is stored in GitHub」を選択します。
「Connect with GitHub」をクリックすると、ポップアップで GitHub の OAuth 認証画面が表示されます。
認証後、Repository Name と Commit ID を指定します。Repository Name はアカウント名または Organization 名から指定します。
準備完了!「Deploy Now」をクリックしてデプロイを実行します。「Succeed」と表示されれば成功です!
まとめ
とりあえず Rails アプリケーションをデプロイするところまで、ひと通り行ってみました。AppSpec はまだまだ調整の余地はありますし、Capistrano と比べると一番の優位点である Auto Scaling Group を対象としたデプロイという方法もあります。引き続き調査していきたいと思います!